#pragma once
#include "../core.h"

namespace qb {
namespace base {
class S_CORE_EXPORT MD5 {
 public:
  typedef char tMD5[36];
  static bool FromString(const char* szStr, char* md5buf, int len);
  static bool FromString(const char* szStr, int szStrLen, char* md5buf,
                         int len);
  static bool FromFile(const char* szFileName, char* md5buf, int len);
};
}  // namespace base

typedef unsigned int uint4;
typedef unsigned short int uint2;
typedef unsigned char uchar;

S_CORE_EXPORT char* PrintMD5(uchar md5Digest[16]);
S_CORE_EXPORT char* MD5String(const char* szString);
S_CORE_EXPORT char* MD5File(char* szFilename);

S_CORE_EXPORT void Init();
S_CORE_EXPORT void Update(uchar* chInput, uint4 nInputLen);
S_CORE_EXPORT void Finalize();
S_CORE_EXPORT uchar* Digest();  // { return m_Digest; }

S_CORE_EXPORT void Transform(uchar* block);
S_CORE_EXPORT void Encode(uchar* dest, uint4* src, uint4 nLength);
S_CORE_EXPORT void Decode(uint4* dest, uchar* src, uint4 nLength);

inline uint4 rotate_left(uint4 x, uint4 n) {
  return ((x << n) | (x >> (32 - n)));
}

inline uint4 F(uint4 x, uint4 y, uint4 z) { return ((x & y) | (~x & z)); }

inline uint4 G(uint4 x, uint4 y, uint4 z) { return ((x & z) | (y & ~z)); }

inline uint4 H(uint4 x, uint4 y, uint4 z) { return (x ^ y ^ z); }

inline uint4 I(uint4 x, uint4 y, uint4 z) { return (y ^ (x | ~z)); }

inline void FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s,
               uint4 ac) {
  a += F(b, c, d) + x + ac;
  a = rotate_left(a, s);
  a += b;
}

inline void GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s,
               uint4 ac) {
  a += G(b, c, d) + x + ac;
  a = rotate_left(a, s);
  a += b;
}

inline void HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s,
               uint4 ac) {
  a += H(b, c, d) + x + ac;
  a = rotate_left(a, s);
  a += b;
}

inline void II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s,
               uint4 ac) {
  a += I(b, c, d) + x + ac;
  a = rotate_left(a, s);
  a += b;
}

static unsigned char PADDING[64] = {
    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

}  // namespace qb
